﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MacomberMapSystem.Common.Serialization;
using System.ComponentModel;
using System.Xml;
using System.Data.Common;
using MacomberMapSystem.Common.CIM;
using MacomberMapSystem.Common.Database;

namespace MacomberMapSystem.Common.Processing
{
    /// <summary>
    /// This class is responsible for removing linkages from elements
    /// </summary>
    public class CIM_LinkageRemover: CIM_Processor
    {
        #region Variable declarations
        /// <summary>
        /// Our collection of linkages to remove
        /// </summary>
        public List<CIM_LinkageToRemove> LinkagesToRemove
        {
            get { return _LinkagesToRemove; }
            set { _LinkagesToRemove = value; }
        }

        private List<CIM_LinkageToRemove> _LinkagesToRemove = new List<CIM_LinkageToRemove>();
        
        /// <summary>Report the name of our process</summary>
        public override string ProcessName
        {
            get { return "Linkage remover"; }
        }
        #endregion

        #region Initialization/execution
        /// <summary>
        /// Initialize a new linkage remover
        /// </summary>
        /// <param name="xElem"></param>
        /// <param name="NamedParameters"></param>
        /// <param name="Repository"></param>
        public CIM_LinkageRemover(XmlElement xElem, Dictionary<String, Object> NamedParameters, MM_Repository Repository)
            : base(xElem, NamedParameters, Repository)
        {            
            foreach (XmlElement xLinkToRemove in xElem.SelectNodes("LinkageToRemove"))
                LinkagesToRemove.Add(new CIM_LinkageToRemove(xLinkToRemove, Repository));

        }

        /// <summary>
        /// Execute our process
        /// </summary>
        /// <param name="DbConn"></param>
        /// <returns></returns>
        public override CIM_Processor.enumProcessState InitiateProcess(MM_Database_Connector DbConn)
        {

            MM_Database_Model CIM = NamedParameters["Model"] as MM_Database_Model;
            foreach (CIM_LinkageToRemove LinkToRemove in _LinkagesToRemove)
            {               
                //Pull our elements into their positions
                String[] splStr = LinkToRemove.PathToTest.Split(new char[] { '<', '=', '>' }, StringSplitOptions.RemoveEmptyEntries);                



                foreach (CIM_Element Elem in CIM.ElementsOfType(LinkToRemove.ElementType))
                {
                    CIM_Element[] ImplicatedElements = Elem.Parse(LinkToRemove.PathToTest, Repository, true);
                    CIM_Element[][] Elems = new CIM_Element[splStr.Length][];
                    List<CIM_Element> FoundElems = new List<CIM_Element>();
                    for (int a=0; a < splStr.Length; a++)
                    {
                        FoundElems.Clear();
                        foreach (CIM_Element Elem2 in ImplicatedElements)
                            if (Elem2.TypeName.EndsWith(splStr[a], StringComparison.CurrentCultureIgnoreCase))
                                FoundElems.Add(Elem2);
                        Elems[a] = FoundElems.ToArray();
                    }




                    if (LinkToRemove.RemoveElements == CIM_LinkageToRemove.EnumRemoveElements.RemoveAllElements)
                        foreach (CIM_Element Elem2 in ImplicatedElements)
                            CIM_Element_Difference.RemoveElement(Elem2);
                    else if (LinkToRemove.RemoveElements == CIM_LinkageToRemove.EnumRemoveElements.RemoveFirstElement)
                    {
                        foreach (CIM_Element Elem2 in ImplicatedElements)
                            if (Elem2.TypeName.EndsWith(splStr[0], StringComparison.CurrentCultureIgnoreCase))
                                CIM_Element_Difference.RemoveElement(Elem2);
                    }
                    else if (LinkToRemove.RemoveElements == CIM_LinkageToRemove.EnumRemoveElements.RemoveAllLinks)
                    {
                        //First, remove the linkages from the source element to the next
                        foreach (CIM_Element Elem2 in ImplicatedElements)
                            if (Elem2.TypeName.EndsWith(splStr[0], StringComparison.CurrentCultureIgnoreCase))
                                CIM_Element_Difference.RemoveLinkage(Elem, Elem2);
                        //Now, remove the rest of the linkages
                        for (int a = 0; a < splStr.Length - 1; a++)
                            foreach (CIM_Element Elem2 in Elems[a])
                                foreach (CIM_Element Elem3 in Elems[a + 1])
                                    CIM_Element_Difference.RemoveLinkage(Elem2, Elem3);
                    }
                    else if (LinkToRemove.RemoveElements == CIM_LinkageToRemove.EnumRemoveElements.RemoveFirstLink)
                    {
                        foreach (CIM_Element Elem2 in ImplicatedElements)
                            if (Elem2.TypeName.EndsWith(splStr[0], StringComparison.CurrentCultureIgnoreCase))
                                CIM_Element_Difference.RemoveLinkage(Elem, Elem2);                        
                    }
                            



                }                 
            }
            return enumProcessState.Completed;
        }
        #endregion

        /// <summary>
        /// This class holds information on a linkage to be removed
        /// </summary>
        public class CIM_LinkageToRemove: MM_Serializable
        {
            #region Variable declarations
            /// <summary>The type associated with the seed element</summary>
            [Category("Configuration"), Description("The type associated with the seed element"), MM_Serializable_Target(MM_Serializable_Target.enumTargetType.FieldValue)]
            public string ElementType
            {
                get { return _ElementType; }
                set { _ElementType = value; }
            }

            /// <summary>The path to be tested</summary>
            [Category("Configuration"), Description("The path to be tested"), MM_Serializable_Target(MM_Serializable_Target.enumTargetType.FieldValue)]
            public string PathToTest
            {
                get { return _PathToTest; }
                set { _PathToTest = value; }
            }
            private EnumRemoveElements _RemoveElements;

            /// <summary>The type associated with the seed element</summary>
            [Category("Configuration"), Description("The link removal type that should be practiced"), MM_Serializable_Target(MM_Serializable_Target.enumTargetType.FieldValue)]                    
            public EnumRemoveElements RemoveElements
            {
                get { return _RemoveElements; }
                set { _RemoveElements = value; }
            }
            private string _ElementType, _PathToTest;
            
            /// <summary>
            /// The enumeration of removals that can be handled
            /// </summary>
            public enum EnumRemoveElements
            {
                /// <summary>Remove the link from the primary element down the path</summary>
                RemoveFirstLink,
                /// <summary>Remove all linkages from the primary element down the path</summary>
                RemoveAllLinks,
                /// <summary>Remove the primary links and the first element</summary>
                RemoveFirstElement,
                /// <summary>Remove all elements</summary>
                RemoveAllElements
            }
            #endregion

            #region Initialization
            /// <summary>
            /// Initialize a new CIM linkage to be removed
            /// </summary>
            /// <param name="xElem"></param>
            /// <param name="Repository"></param>
            public CIM_LinkageToRemove(XmlElement xElem, MM_Repository Repository)
                : base(xElem, Repository)
            {
            }

            /// <summary>
            /// Intialize a new CIM linkage to be removed
            /// </summary>
            /// <param name="dRd"></param>
            /// <param name="xDoc"></param>
            /// <param name="Repository"></param>
            public CIM_LinkageToRemove(DbDataReader dRd, XmlDocument xDoc, MM_Repository Repository)
                : base(dRd, xDoc, Repository)
            {
            }
            #endregion
        }


    }
}
